﻿using System;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Security.Permissions;
using System.Windows;
using System.Windows.Input;
using AdTech.Common.WPF;
using Hardcodet.Wpf.TaskbarNotification;

namespace AdTech.Snap
{
    #pragma warning disable 1591
    public class MainViewModel : ViewModelBase, IBalloonTipHost
    {
        // Fields
        private const Key Hotkey = Key.PrintScreen;
        private const ModifierKeys HotkeyModifiers = ModifierKeys.None;
        private readonly ISnapFactory snapFactory;
        private readonly IDropboxFactory dropboxFactory;
        private readonly IQRCodeFactory qrcodeFactory;
        private string destination;
        private string _ToolTip;
        private DelegateCommand _NewScreenshotCommand;
        private DelegateCommand _ConfigureCommand;
        private DelegateCommand _OpenDestinationCommand;
        private DelegateCommand<RoutedEventArgs> _TrayBalloonTipClickedCommand;
        private DelegateCommand _EnableGlobalHotkeyCommand;

        // Properties
        /// <summary>
        /// Gets the Text to display in the ToolTip
        /// </summary>
        public string ToolTip
        {
            get { return _ToolTip; }
            set { if (value == _ToolTip) return; _ToolTip = value; NotifyPropertyChanged(() => this.ToolTip); }
        }
        public bool IsHotkeyEnabled
        {
            get { return this.HotkeyInterface != null ? this.HotkeyInterface.IsRegistered : false; }
            set { if (this.HotkeyInterface != null && value != this.HotkeyInterface.IsRegistered) this.HotkeyInterface.IsRegistered = value; NotifyPropertyChanged(() => this.IsHotkeyEnabled); }
        }
        public IConfiguration Configuration { get; set; }
        public GlobalKeyboardHook HotkeyInterface { get; set; }
        public Action<string, string, BalloonIcon> ShowBalloonTip { get; set; }

        #region Commands
        public ICommand NewScreenshotCommand
        {
            get
            {
                if (_NewScreenshotCommand == null)
                    _NewScreenshotCommand = new DelegateCommand(OnExecuteNewScreenshot, OnCanExecuteNewScreenshot);
                return _NewScreenshotCommand;
            }
        }
        public ICommand ConfigureCommand
        {
            get
            {
                if (_ConfigureCommand == null)
                    _ConfigureCommand = new DelegateCommand(OnExecuteConfigure, OnCanExecuteConfigure);
                return _ConfigureCommand;
            }
        }
        public ICommand OpenDestinationCommand
        {
            get
            {
                if (_OpenDestinationCommand == null)
                    _OpenDestinationCommand = new DelegateCommand(OnExecuteOpenDestination, OnCanExecuteOpenDestination);
                return _OpenDestinationCommand;
            }
        }
        public ICommand EnableGlobalHotkeyCommand
        {
            get
            {
                if (_EnableGlobalHotkeyCommand == null)
                    _EnableGlobalHotkeyCommand = new DelegateCommand(OnExecuteEnableGlobalHotkey, OnCanExecuteEnableGlobalHotkey);
                return _EnableGlobalHotkeyCommand;
            }
        }
        public ICommand TrayBalloonTipClickedCommand
        {
            get
            {
                if (_TrayBalloonTipClickedCommand == null)
                    _TrayBalloonTipClickedCommand = new DelegateCommand<RoutedEventArgs>(OnExecuteTrayBalloonTipClicked);
                return _TrayBalloonTipClickedCommand;
            }
        }
        #endregion

        /// <summary>
        /// Initializes a new Window of Snap
        /// </summary>
        public MainViewModel(IConfiguration config, ISnapFactory snapFactory, IDropboxFactory dropboxFactory, IQRCodeFactory qrcodeFactory)
        {
            this.Configuration = config;
            this.snapFactory = snapFactory;
            this.dropboxFactory = dropboxFactory;
            this.qrcodeFactory = qrcodeFactory;
            this.ToolTip = GenerateToolTip();
            this.SetupHotkey();
        }

        #region Commands
        protected virtual bool OnCanExecuteNewScreenshot()
        {
            return !Application.Current.Windows.OfType<Overlay>().Any() && !this.Configuration.IsNew ||
                   !Application.Current.Windows.OfType<Overlay>().Any() && this.ConfigureCommand.CanExecute(null);
        }
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
        protected virtual void OnExecuteNewScreenshot()
        {
            if (!ValidateConfiguration())
                return;

            OverlayViewModel vm = new OverlayViewModel(this.Configuration, this.snapFactory, this.dropboxFactory);
            Overlay wnd = new Overlay { DataContext = vm };
            vm.RequestClose = () => wnd.Close();
            try
            {
                if (wnd.ShowDialog().Equals(true))
                {
                    OnShowBalloonTip(vm.DestinationPath);
                    PrintQRCode(vm.PublicLink);
                }
            }
            catch (Exception)
            {
                ShowErrorBalloonTip();
            }
        }

        protected virtual bool OnCanExecuteConfigure()
        {
            return !Application.Current.Windows.OfType<ConfigDialog>().Any();
        }
        protected virtual void OnExecuteConfigure()
        {
            ConfigViewModel vm = new ConfigViewModel(this.Configuration, this.dropboxFactory);
            ConfigDialog wnd = new ConfigDialog { DataContext = vm };
            vm.RequestClose = () => wnd.Close();
            wnd.ShowDialog();
        }

        protected virtual bool OnCanExecuteOpenDestination()
        {
            return true;
        }
        [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
        protected virtual void OnExecuteOpenDestination()
        {
            try
            {
                Process.Start("explorer.exe", this.Configuration.DefaultFileDestination);
            }
            catch { }
        }

        protected virtual bool OnCanExecuteEnableGlobalHotkey()
        {
            return true;
        }
        protected virtual void OnExecuteEnableGlobalHotkey()
        {
            this.IsHotkeyEnabled = !this.IsHotkeyEnabled;
        }

        [PermissionSetAttribute(SecurityAction.LinkDemand, Name = "FullTrust")]
        protected virtual void OnExecuteTrayBalloonTipClicked(RoutedEventArgs args)
        {
            try
            {
                Process.Start("explorer.exe", String.Concat("/select,", destination));
            }
            catch { }
        }
        #endregion

        protected bool ValidateConfiguration()
        {
            // Check if configuration exists
            if (this.Configuration.IsNew)
            {
                ConfigViewModel vm = new ConfigViewModel(this.Configuration, this.dropboxFactory);
                ConfigDialog wnd = new ConfigDialog { DataContext = vm };
                vm.RequestClose = () => wnd.Close();
                return wnd.ShowDialog().Equals(true);
            }
            return true;
        }

        protected void OnShowBalloonTip(string resultpath)
        {
            //string header = String.Format("Snap v{0} Beta", Assembly.GetExecutingAssembly().GetName().Version);
            string result = String.Format("Successfully created screenshot at {0}.", resultpath);
            if (this.Configuration.UseDropbox)
                result += "\nPublic Dropbox Link has been copied to clipboard.";
            this.destination = resultpath;
            
            if (this.ShowBalloonTip != null)
                this.ShowBalloonTip("Snap", result, BalloonIcon.Info);
        }

        protected void ShowErrorBalloonTip()
        {
            if (this.ShowBalloonTip != null)
                this.ShowBalloonTip("An error ocurred in Snap", "See the event log for more details.", BalloonIcon.Error);
        }

        protected void PrintQRCode(string publicURL)
        {
            // Show QRCode
            if (this.Configuration.UseDropbox && this.Configuration.CreateQRCode)
            {
                Window w = new Window
                {
                    ResizeMode = System.Windows.ResizeMode.NoResize,
                    WindowStyle = WindowStyle.ToolWindow,
                    Title = "Snap - Generated QRCode",
                    SizeToContent = SizeToContent.WidthAndHeight,
                    WindowStartupLocation = WindowStartupLocation.CenterScreen
                };
                w.Content = this.qrcodeFactory.EncodeAsXaml(publicURL);
                w.Show();
            }
        }

        protected void SetupHotkey()
        {
            // Hook global hotkey override
            this.HotkeyInterface = new GlobalKeyboardHook(Application.Current.MainWindow, Hotkey, HotkeyModifiers);
            this.HotkeyInterface.HotkeyTriggered += (sender, e) => 
            { 
                if (this.HotkeyInterface.IsRegistered && this.NewScreenshotCommand.CanExecute(true))
                    this.NewScreenshotCommand.Execute(true); 
            };
            this.HotkeyInterface.RegisterHotkey();
        }

        private string GenerateToolTip()
        {
            return String.Format("Snap v{0}\nDropbox Integration {1}", Assembly.GetExecutingAssembly().GetName().Version, this.Configuration.UseDropbox ? "Enabled" : "Disabled");
        }
    }
    #pragma warning restore 1591
}
